﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using QUT.Gppg;

namespace ConceptsParser.SyntaxTree
{
    public static class LexLocationExtension
    {
        public static string ToStringGood(this LexLocation location)
        {
            return ParserTools.ParserToolsManager.LexLocation_ToString(location);
        }
    }

    /// <summary>
    /// Базовый класс узлов синтаксического дерева
    /// </summary>
    public abstract class ConceptsSyntaxTreeNode 
    {
        private LexLocation location;

        public LexLocation Location
        {
            get { return location; }
        }

        public ConceptsSyntaxTreeNode(LexLocation location)
        {
            SetNewLocation(location);
        }

        public void SetNewLocation(LexLocation location)
        {
            if (location == null)
                //throw new ArgumentNullException("location can not be null");
                this.location = new LexLocation(-1, -1, -1, -1);
            else
                this.location = location;
        }

        public virtual void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            throw new NotImplementedException();
        }
    }

    // ================================== Основные блоки

    /// <summary>
    /// Вся программа
    /// </summary>
    public class ProgramNode : ConceptsSyntaxTreeNode 
    {
        private UsingSectionNode usingSection;
        private ConceptsSectionNode conceptsSection;

        public UsingSectionNode UsingSection
        {
            get { return usingSection; }
        }
        public ConceptsSectionNode ConceptsSection
        {
            get { return conceptsSection; }
        }

        public ProgramNode(LexLocation location, UsingSectionNode usingSection, ConceptsSectionNode conceptsSection)
            : base(location)
        {
            if (usingSection == null)
                throw new ArgumentNullException("usingSection can not be null");
            if (conceptsSection == null)
                throw new ArgumentNullException("conceptsSection can not be null");
            this.usingSection = usingSection;
            this.conceptsSection = conceptsSection;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    public class ProgramSectionNode : ConceptsSyntaxTreeNode 
    {
        public ProgramSectionNode(LexLocation location)
            : base(location)
        { }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            throw new NotImplementedException();
        }
    }

    public class DeclarationNode : ConceptsSyntaxTreeNode 
    {
        public DeclarationNode(LexLocation location)
            : base(location)
        { }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            throw new NotImplementedException();
        }
    }

    public class DirectiveNode : ConceptsSyntaxTreeNode 
    {
        public DirectiveNode(LexLocation location)
            : base(location)
        { }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            throw new NotImplementedException();
        }
    }

    public class DefinitionNode : ConceptsSyntaxTreeNode 
    {
        public DefinitionNode(LexLocation location)
            : base(location)
        { }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            throw new NotImplementedException();
        }
    }

    // ================================== Идентификаторы

    public class QualifiedNamespaceNode : ConceptsSyntaxTreeNode
    {
        private LinkedList<string> fullNamespaceName;

        public QualifiedNamespaceNode(LexLocation location, string innerName) 
            : base(location)
        {
            if ((innerName == null) || (innerName == ""))
                throw new ArgumentOutOfRangeException("innerName can not be empty");
            fullNamespaceName = new LinkedList<string>();
            fullNamespaceName.AddLast(innerName);
        }

        public QualifiedNamespaceNode(LexLocation location, LinkedList<string> fullNamespaceName)
            : base(location)
        {
            if (fullNamespaceName == null)
                throw new ArgumentNullException("fullNamespaceName can not be null");
            this.fullNamespaceName = fullNamespaceName;
        }

        public override string ToString()
        {
            System.Diagnostics.Debug.Assert(fullNamespaceName.Count >= 1,
                String.Format("QualifiedNamespaceNode: fullNamespaceName.Count >= 1 | {0}",
                fullNamespaceName.Count));
            StringBuilder sb = new StringBuilder();
            var enumer = fullNamespaceName.GetEnumerator();
            for (int i = 0; i < fullNamespaceName.Count - 1; ++i )
            {
                enumer.MoveNext();
                sb.Append(enumer.Current + ".");
            }
            enumer.MoveNext();
            sb.Append(enumer.Current);
            return sb.ToString();
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Единица квалификатора типа
    /// </summary>
    public abstract class TypeQualifierNode : ConceptsSyntaxTreeNode, IEquatable<TypeQualifierNode>
    {
        public TypeQualifierNode(LexLocation location)
            : base(location)
        { }

        public virtual bool Equals(TypeQualifierNode other)
        {
            throw new NotImplementedException();
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Квалификатор типа в форме идентификатора
    /// </summary>
    public class IDTypeQualifierNode : TypeQualifierNode 
    {
        private string name;
        
        ///// <summary>
        ///// Идентификатор
        ///// </summary>
        //public string Name
        //{
        //    get { return name; }
        //}

        public IDTypeQualifierNode(LexLocation location, string name)
            : base(location)
        {
            if ((name == null) || (name == ""))
                throw new ArgumentOutOfRangeException("name can not be empty");
            this.name = name;
        }

        public override bool Equals(TypeQualifierNode other)
        {
            IDTypeQualifierNode otherGood = other as IDTypeQualifierNode;
            if (otherGood == null)
                return false;
            return (this.name == otherGood.name);
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }

        public override string ToString()
        {
            return name;
        }
    }

    /// <summary>
    /// Квалификатор типа в форме ссылки на концепт
    /// </summary>
    public class ConceptReferenceQualifierNode : TypeQualifierNode 
    {
        private ConceptReferenceNode conceptRef;

        public ConceptReferenceQualifierNode(LexLocation location, ConceptReferenceNode conceptRef)
            : base(location)
        {
            if (conceptRef == null)
                throw new ArgumentNullException("conceptRef can not be null");
            this.conceptRef = conceptRef;
        }

        public override bool Equals(TypeQualifierNode other)
        {
            ConceptReferenceQualifierNode otherGood = other as ConceptReferenceQualifierNode;
            if (otherGood == null)
                return false;
            return this.conceptRef.Equals(otherGood.conceptRef);
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Указание типа
    /// </summary>
    public abstract class TypeArgumentNode : ConceptsSyntaxTreeNode, IEquatable<TypeArgumentNode>
    {
        /// <summary>
        /// Непосредственное имя типа
        /// </summary>
        protected string typeName;
        /// <summary>
        /// Список — полный квалификатор типа
        /// </summary>
        protected LinkedList<TypeQualifierNode> typeQualifier;

        public string TypeName
        { get { return typeName; } }
        public LinkedList<TypeQualifierNode> TypeQualifier
        { get { return typeQualifier; } }

        public virtual string NETTypeName
        { get { return typeName; } }

        public string TypeQualifierString
        {
            get 
            {
                if (typeQualifier.Count == 0)
                    return "";
                StringBuilder sb = new StringBuilder();
                var enumer = typeQualifier.GetEnumerator();
                for (int i = 0; i < typeQualifier.Count - 1; ++i)
                {
                    enumer.MoveNext();
                    sb.Append(enumer.Current + ".");
                }
                enumer.MoveNext();
                sb.Append(enumer.Current);
                return sb.ToString();
            }
        }
        public string FullTypeQualifierString
        { 
            get 
            {
                if (typeQualifier.Count == 0)
                    return "";
                else
                    return this.TypeQualifierString + ".";
            } 
        }

        public TypeArgumentNode(LexLocation location, string typeName)
            : base(location)
        {
            _SetTypeName(typeName);
            typeQualifier = new LinkedList<TypeQualifierNode>();
        }

        public TypeArgumentNode(LexLocation location, string typeName, LinkedList<TypeQualifierNode> typeQualifier) 
            : base(location)
        {
            _SetTypeName(typeName);
            SetQualifier(typeQualifier);
        }

        public void SetQualifier(LinkedList<TypeQualifierNode> typeQualifier)
        {
            if (typeQualifier == null)
                throw new ArgumentNullException("typeQualifier can not be null");
            this.typeQualifier = typeQualifier;
        }

        private void _SetTypeName(string typeName)
        {
            if ((typeName == null) || (typeName == ""))
                throw new ArgumentOutOfRangeException("typeName can not be empty");
            this.typeName = typeName;
        }

        public virtual bool Equals(TypeArgumentNode other)
        {
            return (this.typeName == other.typeName)
                && this.typeQualifier.SequenceEqual(other.typeQualifier);
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            throw new NotImplementedException();
        }

        public override string ToString()
        {
            return this.FullTypeQualifierString + this.NETTypeName;
        }
    }

    /// <summary>
    /// Указание простого типа
    /// </summary>
    public class SimpleTypeArgumentNode : TypeArgumentNode 
    {
        public SimpleTypeArgumentNode(LexLocation location, string typeName)
            : base(location, typeName) { }
        public SimpleTypeArgumentNode(LexLocation location, string typeName, LinkedList<TypeQualifierNode> typeQualifier)
            : base(location, typeName, typeQualifier) { }

        public override bool Equals(TypeArgumentNode other)
        {
            SimpleTypeArgumentNode otherGood = other as SimpleTypeArgumentNode;
            if (otherGood == null)
                return false;
            return base.Equals(other);
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Указание обобщённого типа
    /// </summary>
    public class GenericTypeArgumentNode : TypeArgumentNode
    {
        /// <summary>
        /// Список типовых аргументов
        /// </summary>
        protected LinkedList<TypeArgumentNode> typeArgs;

        public LinkedList<TypeArgumentNode> TypeArguments
        { get { return typeArgs; } }

        public GenericTypeArgumentNode(LexLocation location, string typeName, LinkedList<TypeArgumentNode> typeArgs)
            : base(location, typeName)
        {
            _SetTypeArgs(typeArgs);
        }

        private void _SetTypeArgs(LinkedList<TypeArgumentNode> typeArgs)
        {
            if (typeArgs == null)
                throw new ArgumentNullException("typeArgs can not be null");
            if (typeArgs.Count == 0)
                throw new ArgumentOutOfRangeException("typeArgs.Count must be > 0");
            this.typeArgs = typeArgs;
        }

        public override bool Equals(TypeArgumentNode other)
        {
            GenericTypeArgumentNode otherGood = other as GenericTypeArgumentNode;
            if (otherGood == null)
                return false;
            if (!base.Equals(other))
                return false;
            return this.typeArgs.SequenceEqual(otherGood.typeArgs);
        }

        public override string NETTypeName
        {
            get
            {
                return base.NETTypeName + '`' + typeArgs.Count.ToString();
            }
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    // ================================== Секция пространств имён

    /// <summary>
    /// Секция подключения пространств имён
    /// </summary>
    public class UsingSectionNode : ProgramSectionNode
    {
        private LinkedList<UsingDirectiveNode> directives;

        public LinkedList<UsingDirectiveNode> Directives
        {
            get { return directives; }
        }

        public UsingSectionNode(LexLocation location) 
            : base(location)
        {
            directives = new LinkedList<UsingDirectiveNode>();
        }

        public void AddUsingDirective(UsingDirectiveNode newDirective)
        {
            if (newDirective == null)
                throw new ArgumentNullException("newDirective can not be null");
            directives.AddLast(newDirective);
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Директива подключения пространства имён
    /// </summary>
    public class UsingDirectiveNode : DirectiveNode 
    {
        private QualifiedNamespaceNode qualifiedNamespace;

        public QualifiedNamespaceNode QualifiedNamespace
        {
            get { return qualifiedNamespace; }
        }

        public UsingDirectiveNode(LexLocation location, QualifiedNamespaceNode qualifiedNamespace)
            : base(location)
        {
            if (qualifiedNamespace == null)
                throw new ArgumentNullException("qualifiedNamespace can not be null");
            this.qualifiedNamespace = qualifiedNamespace;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    // ================================== Секция концептов

    /// <summary>
    /// Оператор ограничения на тип
    /// </summary>
    /// <value="EQUAL">Ограничение равенства</value>
    /// <value="SUBTYPE">Ограничение подтипирования</value>
    /// <value="SUPERTYPE">Ограничение надтипирования</value>
    public enum TypeConstraintOperator { EQUAL, SUBTYPE, SUPERTYPE };

    /// <summary>
    /// Секция определения концептов
    /// </summary>
    public class ConceptsSectionNode : ProgramSectionNode 
    {
        private LinkedList<ConceptDefinitionNode> concepts;

        public LinkedList<ConceptDefinitionNode> Concepts
        {
            get { return concepts; }
        }

        public ConceptsSectionNode(LexLocation location) 
            : base(location)
        {
            concepts = new LinkedList<ConceptDefinitionNode>();
        }

        public void AddConceptDefinition(ConceptDefinitionNode conceptDef)
        {
            if (conceptDef == null)
                throw new ArgumentNullException("conceptDef can not be null");
            concepts.AddLast(conceptDef);
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Определение концепта
    /// </summary>
    public class ConceptDefinitionNode : DefinitionNode 
    {
        /// <summary>
        /// Является ли концепт явным
        /// </summary>
        private bool isExplicit;
        private ConceptSignatureNode signature;
        private ConceptSignatureNode refinement;
        private ConceptBodyNode body;

        /// <summary>
        /// Возвращает или задаёт значение явности концепта
        /// </summary>
        public bool IsExplicit
        {
            get { return isExplicit; }
            set { isExplicit = value; }
        }
        public ConceptSignatureNode Signature
        { get { return signature; } }
        public ConceptSignatureNode Refinement
        { get { return refinement; } }
        public ConceptBodyNode Body
        { get { return body; } }

        public ConceptDefinitionNode(LexLocation location, ConceptSignatureNode signature, ConceptSignatureNode refinement, ConceptBodyNode body)
            : base(location)
        {
            if (signature == null)
                throw new ArgumentNullException("signature can not be null");
            if (body == null)
                throw new ArgumentNullException("body can not be null");
            this.isExplicit = false;
            this.signature = signature;
            if (refinement != null)
                refinement.IsNewConceptDef = false;
            this.refinement = refinement;
            this.body = body;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Концепт с типовыми параметрами
    /// </summary>
    public class ConceptSignatureNode : ConceptsSyntaxTreeNode 
    {
        /// <summary>
        /// Имя концепта
        /// </summary>
        private string name;
        /// <summary>
        /// Список типовых параметров
        /// </summary>
        private LinkedList<string> typeParams;

        public bool IsNewConceptDef;

        public string Name
        { get { return name; } }
        /// <summary>
        /// Список типовых параметров концепта
        /// </summary>
        public LinkedList<string> TypeParams
        { get { return typeParams; } }

        public ConceptSignatureNode(LexLocation location, string name, LinkedList<string> typeParams)
            : base(location)
        {
            if ((name == null) || (name == ""))
                throw new ArgumentOutOfRangeException("name can not be empty");
            if (typeParams == null)
                throw new ArgumentNullException("typeParams can not be null");
            if (typeParams.Count == 0)
                throw new ArgumentOutOfRangeException("typeParams.Count must be > 0");
            this.name = name;
            this.typeParams = typeParams;
            this.IsNewConceptDef = true;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Тело концепта
    /// </summary>
    public class ConceptBodyNode : ConceptsSyntaxTreeNode 
    {
        private LinkedList<InnerConceptDeclarationNode> declarations;

        public LinkedList<InnerConceptDeclarationNode> Declarations
        { get { return declarations; } }

        public ConceptBodyNode(LexLocation location)
            : base(location)
        {
            declarations = new LinkedList<InnerConceptDeclarationNode>();
        }

        public ConceptBodyNode(LexLocation location, LinkedList<InnerConceptDeclarationNode> declarations)
            : base(location)
        {
            if (declarations == null)
                throw new ArgumentNullException("declarations can not be null");
            this.declarations = declarations;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Указание концепта
    /// </summary>
    public class ConceptReferenceNode : ConceptsSyntaxTreeNode, IEquatable<ConceptReferenceNode> 
    {
        /// <summary>
        /// Имя концепта
        /// </summary>
        private string name;
        /// <summary>
        /// Список типовых аргументов
        /// </summary>
        private LinkedList<TypeArgumentNode> typeArgs;

        public ConceptReferenceNode(LexLocation location, string name, LinkedList<TypeArgumentNode> typeArgs)
            : base(location)
        {
            if ((name == null) || (name == ""))
                throw new ArgumentOutOfRangeException("name can not be empty");
            if (typeArgs == null)
                throw new ArgumentNullException("typeArgs can not be null");
            if (typeArgs.Count == 0)
                throw new ArgumentOutOfRangeException("typeArgs.Count must be > 0");
            this.name = name;
            this.typeArgs = typeArgs;
        }

        public bool Equals(ConceptReferenceNode other)
        {
            bool result = this.name == other.name;
            if (result)
                result = this.typeArgs.Count == other.typeArgs.Count;
            if (result)
            {
                var thisCurr = this.typeArgs.GetEnumerator();
                var otherCurr = other.typeArgs.GetEnumerator();
                while (thisCurr.MoveNext() && otherCurr.MoveNext())
                    result = result && (thisCurr.Current.Equals(otherCurr.Current));
            }
            return result;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Объявление в концепте
    /// </summary>
    public class InnerConceptDeclarationNode : DeclarationNode 
    {
        public InnerConceptDeclarationNode(LexLocation location)
            : base(location) 
        { }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Объявление-требование
    /// </summary>
    public class InnerConceptRequirementNode : InnerConceptDeclarationNode 
    {
        public InnerConceptRequirementNode(LexLocation location)
            : base(location)
        { }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Объявление-алиас
    /// </summary>
    public class InnerConceptAliasNode : InnerConceptDeclarationNode
    {
        public InnerConceptAliasNode(LexLocation location)
            : base(location)
        { }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Вложенное требование на концепт
    /// </summary>
    public class NestedConceptRequirementNode : InnerConceptRequirementNode 
    {
        private ConceptReferenceNode conceptRef;
        private string alias;

        public NestedConceptRequirementNode(LexLocation location, ConceptReferenceNode conceptRef, string alias)
            : base(location)
        {
            if (conceptRef == null)
                throw new ArgumentNullException("conceptRef can not be null");
            if ((alias == null) || (alias == ""))
                this.alias = "";
            this.conceptRef = conceptRef;
            this.alias = alias;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Требование ассоциированного типа (возможно, с ограничением)
    /// </summary>
    public class AssociatedTypeDeclarationNode : InnerConceptRequirementNode 
    {
        private string assocTypeName;
        private ConstraintOnTypeArgNode constraint;

        public string AssociatedTypeName
        { get { return assocTypeName; } }
        public ConstraintOnTypeArgNode Constraint
        { get { return constraint; } }

        public AssociatedTypeDeclarationNode(LexLocation location, string assocTypeName, ConstraintOnTypeArgNode constraint)
            : base(location)
        {
            if ((assocTypeName == null) || (assocTypeName == ""))
                throw new ArgumentOutOfRangeException("assocTypeName can not be empty");
            this.assocTypeName = assocTypeName;
            this.constraint = constraint;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Ограничение на некоторый тип
    /// </summary>
    public class ConstraintOnTypeArgNode : ConceptsSyntaxTreeNode 
    {
        private TypeArgumentNode rightTypeArg;
        private TypeConstraintOperator constraintOp;

        public TypeArgumentNode RightTypeArgument
        { get { return rightTypeArg; } }
        public TypeConstraintOperator Operator
        { get { return constraintOp; } }

        public ConstraintOnTypeArgNode(LexLocation location, TypeArgumentNode rightTypeArg, TypeConstraintOperator constraintOp)
            : base(location)
        {
            if (rightTypeArg == null)
                throw new ArgumentNullException("rightTypeArg can not be null");
            this.rightTypeArg = rightTypeArg;
            this.constraintOp = constraintOp;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Типовое ограничение
    /// </summary>
    public class TypeRequirementNode : InnerConceptRequirementNode 
    { 
        private TypeArgumentNode leftTypeArg;
        private TypeArgumentNode rightTypeArg;
        private TypeConstraintOperator constraintOp;

        public TypeArgumentNode LeftTypeArgument
        { get { return leftTypeArg; } }
        public TypeArgumentNode RightTypeArg
        { get { return rightTypeArg; } }
        public TypeConstraintOperator Operator
        { get { return constraintOp; } }

        public TypeRequirementNode(LexLocation location, TypeArgumentNode leftTypeArg, TypeArgumentNode rightTypeArg, TypeConstraintOperator constraintOp)
            : base(location)
        {
            if (leftTypeArg == null)
                throw new ArgumentNullException("leftTypeArg can not be null");
            if (rightTypeArg == null)
                throw new ArgumentNullException("rightTypeArg can not be null");
            this.leftTypeArg = leftTypeArg;
            this.rightTypeArg = rightTypeArg;
            this.constraintOp = constraintOp;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    public class ConceptAliasNode : InnerConceptAliasNode 
    { 
        private string alias;
        private ConceptReferenceNode conceptRef;

        public ConceptAliasNode(LexLocation location, string alias, ConceptReferenceNode conceptRef)
            : base(location)
        {
            if ((alias == null) || (alias == ""))
                throw new ArgumentOutOfRangeException("alias can not be empty");
            if (conceptRef == null)
                throw new ArgumentNullException("conceptRef can not be null");
            this.conceptRef = conceptRef;
            this.alias = alias;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    public class TypeAliasNode : InnerConceptAliasNode 
    {
        private string alias;
        private TypeArgumentNode typeArg;

        public string Alias
        { get { return alias; } }
        public TypeArgumentNode TypeArgument
        { get { return typeArg; } }

        public TypeAliasNode(LexLocation location, string alias, TypeArgumentNode typeArg)
            : base(location)
        {
            if ((alias == null) || (alias == ""))
                throw new ArgumentOutOfRangeException("alias can not be empty");
            if (typeArg == null)
                throw new ArgumentNullException("typeArg can not be null");
            this.typeArg = typeArg;
            this.alias = alias;
        }

        public override void AcceptVisitor(ISyntaxTreeVisitor visitor)
        {
            visitor.Visit(this);
        }
    }
}
